/**
 * Copyright (c) 2006-2012 Las Venturas Playground, LVP Mineground
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package mineground.bukkit;

import org.bukkit.Location;

import mineground.core.MessageLoop;
import mineground.core.MessageLoopThread;
import mineground.entities.Player;
import mineground.entities.PlayerBaseImpl;
import mineground.entities.requests.LocationRunnable;
import mineground.util.Vector3D;

/**
 * This is the Native Player class extending the Player Base implementation, together completing an
 * implementation of the Player interface which will be used throughout the code.
 * 
 * Methods in this class are expected to be thread-safe, and can thus be used from any thread the
 * code runs on. This is very important to keep in mind when new functionality is being added, as
 * Bukkit's own Player APIs are not thread-safe.
 */
public class NativePlayer extends PlayerBaseImpl implements Player {
    /**
     * Given that Bukkit's Player interface is not thread-safe, we want to be sure that such tasks
     * are being executed on the Server Thread rather than the thread we're on. This is included in
     * the Bukkit layer given that future APIs may become thread-safe.
     */
    private static MessageLoop mMessageLoop;
    
    /**
     * Maintain an instance of the native Bukkit Player interface, which will be used to post tasks
     * to on the Server thread when necessary.
     */
    private org.bukkit.entity.Player mBukkitPlayer;
    
    /**
     * Initialize the Native Player class for Bukkit servers. Store Bukkit's instance of the native
     * player and build this class' state around it.
     * 
     * @param bukkitPlayer Bukkit's instance of the Player interface representing this player.
     */
    public NativePlayer(org.bukkit.entity.Player bukkitPlayer) {
        mBukkitPlayer = bukkitPlayer;
        
        // Initialize several non-mutable (or controlled mutability by us) variables which shouldn't
        // change often during run-time, to give direct access to them. See the comment prepending
        // the PlayerBaseImpl class for a list of variables which should be initialized.
        mName = bukkitPlayer.getName();
        mDisplayName = bukkitPlayer.getDisplayName();
    }
    
    /**
     * Request the current location of the entity and execute the callback once it's known.
     * 
     * @param callback The Location Runnable which should be executed.
     */
    public void requestLocation(final LocationRunnable callback) {
        mMessageLoop.postTask(MessageLoopThread.ServerThread, new Runnable() {
           public void run() {
               Location playerLocation = mBukkitPlayer.getLocation();
               callback.run(new Vector3D(playerLocation.getX(), playerLocation.getY(),
                   playerLocation.getZ()), playerLocation.getPitch(), playerLocation.getYaw());
           }
        });
    }
    
    /**
     * Distribute a message to the user, which is to be displayed in their chat box.
     * 
     * @param message The message which should be send to the user.
     */
    public void sendMessage(final String message) {
        mMessageLoop.postTask(MessageLoopThread.ServerThread, new Runnable() {
           public void run() {
               mBukkitPlayer.sendMessage(message);
           }
        });
    }
    
    /**
     * Initialize the to-be-used Message Loop with said instance.
     * 
     * @param messageLoop The message loop which we may use for this instance.
     */
    public static void setMessageLoop(MessageLoop messageLoop) {
        mMessageLoop = messageLoop;
    }
}
